﻿using ArithCollect;
using RazorEngine;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.ServiceModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace UnitTestProject {

    public class Configh {
        internal static string Path_Root { get { return ConfigurationManager.AppSettings["Path_Root"]; } }
        internal static string Path_Vmh { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_Vmh"]; } }
        internal static string Path_Vmentitys { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_Vmentitys"]; } }
        internal static string Path_Caseentitys { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_Caseentitys"]; } }
        internal static string Path_Vmctx { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_Vmctx"]; } }
        internal static string Path_Casectx { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_Casectx"]; } }
        internal static string Path_CaseDb { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_CaseDb"]; } }
        internal static string Path_Simulate { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_Simulate"]; } }
        internal static string Path_ScenDal { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_ScenDal"]; } }
        internal static string Path_ScenWcf { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_ScenWcf"]; } }
        internal static string Path_ScenWapi { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_ScenWapi"]; } }
        internal static string Path_ScenProxy { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_ScenProxy"]; } }
        internal static string Path_Config { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_Config"]; } }
        internal static string Path_VmStyleConverter { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_VmStyleConverter"]; } }
        internal static string Path_VmUiStyle { get { return ConfigurationManager.AppSettings["Path_Root"] + ConfigurationManager.AppSettings["Path_VmUiStyle"]; } }
        internal static string Path_Input { get { return ConfigurationManager.AppSettings["Path_Input"]; } }
        internal static string Path_PublishDir { get { return ConfigurationManager.AppSettings["Path_PublishDir"]; } }
        internal static string IsD { get { return ConfigurationManager.AppSettings["IsD"]; } }
    }
    public class EntityType {
        public string entityName;
        public string EntityName {
            get {
                return Regex.Match(entityName, @"\w+(?=Model\b)").Value;
            }
        }
        public List<EntityProp> props;
        public EntityType() { props = new List<EntityProp>(); }
    }
    public class EntityProp {
        public string propName;
        public string propTypeName;
        public string propGenericType1;
    }
    //
    static public class Gh {
        /**/
        #region simuset
        ///<summary>
        /// 所有仿真sql数据均以，主键为 seed 种子自增值为前提
        ///</summary>
        internal static void ParseAndGenerateSqlScript(simudbsetting simusetobj, string casesql) {
            var simures = new UnitTestProject.tools.root();
            var xdoc = XDocument.Parse(Properties.Resources.simulation);
            simures.ReadXml(xdoc.CreateReader());
            var ran = new Random();
            var simureslendic = new Dictionary<string, int>();
            foreach (DataTable item in simures.Tables) {
                simureslendic.Add(item.TableName, int.Parse(item.Rows[0]["len"].ToString()));
            }
            var fkinfo = new Dictionary<string, int>();
            //initial ok
            var t = typeof(simudbsetting);
            var fs = t.GetFields();
            var sb = new StringBuilder();
            sb.AppendLine("use [master]");
            sb.AppendLine("go");
            var dbname = default(object); var dbaddress = default(object);
            foreach (var f in fs) {
                if (f.Name == "dbname") {
                    dbname = f.GetValue(simusetobj);
                } else if (f.Name == "dbaddress") {
                    dbaddress = f.GetValue(simusetobj);
                }
            }
            sb.AppendLine(string.Format("if exists(select * from sys.databases where name='{0}')", dbname));
            sb.AppendLine(string.Format("DROP DATABASE {0}", dbname));
            sb.AppendLine("go");
            sb.AppendLine(string.Format("CREATE DATABASE {0}", dbname));
            sb.AppendLine(string.Format("CONTAINMENT = NONE on primary(name={0},filename='{1}\\{2}.mdf')", dbname, dbaddress, dbname));
            sb.AppendLine(string.Format("log on(name={0}log,filename='{1}\\{2}.ldf')", dbname, dbaddress, dbname));
            sb.AppendLine("go");
            sb.AppendLine(string.Format("use [{0}]", dbname));
            sb.AppendLine("go");
            sb.AppendLine(casesql);
            sb.AppendLine("go");
            var sb2 = new StringBuilder();
            var sb3 = new StringBuilder();
            foreach (var f in fs) {
                if (f.Name != "dbname" && f.Name != "dbaddress") {
                    var fs2 = f.FieldType.GetFields();
                    var rows = 0; var order = 0;
                    var fv = f.GetValue(simusetobj);
                    foreach (var f2 in fs2) {
                        if (f2.Name == "rows") {
                            rows = int.Parse(f2.GetValue(fv).ToString());
                            if (!fkinfo.ContainsKey(f.Name)) {
                                fkinfo.Add(f.Name, rows);
                            } else {
                                fkinfo[f.Name] = rows;
                            }
                        }
                        if (f2.Name == "order")
                            order = int.Parse(f2.GetValue(fv).ToString());
                        if (f2.Name == "outrows") {
                            var outrows = int.Parse(f2.GetValue(fv).ToString());
                            if (!fkinfo.ContainsKey(f.Name)) {
                                fkinfo.Add(f.Name, rows);
                            } else {
                                fkinfo[f.Name] = outrows;
                                if (outrows > 0 && outrows >= rows) rows = 0;
                            }
                        }
                    }
                    for (int i = 0; i < rows; i++) {
                        sb.AppendFormat("insert into {0}(", f.Name);
                        sb2.Clear(); sb3.Clear();
                        foreach (var f2 in fs2) {//属性层
                            var f2v = f2.GetValue(fv);
                            var f3s = from f3 in f2.FieldType.GetFields() where f3.Name == "simuproptype" select f3;
                            if (f3s.Count() > 0) {
                                simuproptype simuproptypevalue = (simuproptype)(f3s.First().GetValue(f2v));
                                if (f2.Name != "rows" && f2.Name != "order" && simuproptypevalue != simuproptype.seed && simuproptypevalue != simuproptype.media && f2.GetCustomAttributes(typeof(XmlIgnoreAttribute)).Count() == 0) {
                                    SimuField(f2v, f2, simuproptypevalue, sb3, simures, ran, simusetobj, simureslendic, fkinfo);
                                    sb2.AppendFormat("[{0}],", f2.Name);
                                }
                            }
                        }
                        sb2.Remove(sb2.Length - 1, 1);
                        sb3.Remove(sb3.Length - 1, 1);
                        sb.AppendFormat("{0}) values({1})", sb2.ToString(), sb3.ToString());
                        sb.Append(Environment.NewLine);
                    }
                    sb.AppendLine("go");
                }
            }
            var path = Environment.CurrentDirectory;
            var sqlcurrentpath = path.Replace(@"\bin\Release", @"\tools\CurrentBizSimuSet.sql");
            SaveTo(sqlcurrentpath, sb.ToString());
        }

        private static void SimuField(object f2v, FieldInfo f2, simuproptype simuproptypevalue, StringBuilder sb, tools.root simures, Random ran, simudbsetting simusetobj, Dictionary<string, int> simureslendic, Dictionary<string, int> fkinfo) {
            int[] range, minmax; string[] fk_table_col; int enum_count;
            int ran1, ran2, min, max; string table, pk, list_type; ran1 = ran2 = min = max = 0; table = pk = list_type = string.Empty;
            foreach (var item in f2.FieldType.GetFields()) {
                switch (item.Name) {
                    case "range": range = (int[])item.GetValue(f2v); if (range != null) { ran1 = range[0]; ran2 = range[1]; } break;
                    case "minmax": minmax = (int[])item.GetValue(f2v); if (minmax != null) { min = minmax[0]; max = minmax[1]; } break;
                    case "fk_table_col": fk_table_col = (string[])item.GetValue(f2v); if (fk_table_col != null) { table = fk_table_col[0]; pk = fk_table_col[1]; } break;
                    case "enum_count": if (item.GetValue(f2v) != null) enum_count = int.Parse(item.GetValue(f2v).ToString()); break;
                    case "list_type": if (item.GetValue(f2v) != null) list_type = item.GetValue(f2v).ToString(); break;
                }
            }
            switch (simuproptypevalue) {
                case simuproptype.ranint:
                    sb.AppendFormat("{0},", ran.Next(min, max));
                    break;
                case simuproptype.randouble:
                    sb.AppendFormat("{0},", ran.Next(min, max) + ran.NextDouble());
                    break;
                case simuproptype.numstring:
                    var numstring_code = string.Empty;
                    if (ran2 < 9) numstring_code = ran.Next(100000000, 1000000000).ToString();
                    else if (ran2 < 18) numstring_code = string.Format("{0}{1},", ran.Next(100000000, 1000000000), ran.Next(100000000, 1000000000));
                    else if (ran2 < 27) numstring_code = string.Format("{0}{1}{2},", ran.Next(100000000, 1000000000), ran.Next(100000000, 1000000000), ran.Next(100000000, 1000000000));
                    else if (ran2 < 32) numstring_code = string.Format("{0}{1}{2}{3},", ran.Next(100000000, 1000000000), ran.Next(100000000, 1000000000), ran.Next(100000000, 1000000000), ran.Next(100000000, 1000000000));
                    sb.AppendFormat("'{0}',", new string(numstring_code.Take(ran.Next(ran1, ran2)).ToArray()));
                    break;
                case simuproptype.date:
                    sb.AppendFormat("'{0}',", DateTime.Now.AddDays(-ran.Next(10, 10000)).Date);
                    break;
                case simuproptype.time:
                    sb.AppendFormat("'{0}',", DateTime.Now.AddSeconds(ran.Next(1000, 50000)));
                    break;
                case simuproptype.datetime:
                    sb.AppendFormat("'{0}',", DateTime.Now.AddDays(-ran.Next(10, 10000)));
                    break;
                case simuproptype.seed:
                    break;
                case simuproptype.role_name:
                    var cn_surnames = simures.cn_surname.Rows[0][simures.cn_surname.cn_surname_TextColumn].ToString().Split(',');
                    var cn_surname = cn_surnames[ran.Next(simureslendic["cn_surname"])];
                    var cn_names = simures.cn_name.Rows[0][simures.cn_name.cn_name_TextColumn].ToString().Split(',');
                    var cn_name = cn_names[ran.Next(simureslendic["cn_name"])];
                    sb.AppendFormat("'{0}{1}',", cn_surname, cn_name);
                    break;
                case simuproptype.nickname:
                    break;
                case simuproptype.idnum:
                    var idnumtitle = ran.Next(100000, 1000000).ToString();
                    var idnumbirth = DateTime.Now.AddDays(-ran.Next(1200, 22000)).ToString("yyyyMMdd");
                    var idnumtrail = ran.Next(1000, 10000).ToString();
                    sb.AppendFormat("'{0}{1}{2}',", idnumtitle, idnumbirth, idnumtrail);
                    break;
                case simuproptype.token:
                    var tokenlen = ran.Next(4, 8);
                    var tokenchars = new char[tokenlen];
                    var token_en_smallchars = simures.en_smallchar.Rows[0][simures.en_smallchar.en_smallchar_TextColumn].ToString().Split(',');
                    var token_nums = simures.num.Rows[0][simures.num.num_TextColumn].ToString().Split(',');
                    var token_en_smallcharlen = simureslendic["en_smallchar"];
                    var token_numlen = simureslendic["num"];
                    for (int i = 0; i < tokenlen; i++) {
                        tokenchars[i] = ran.Next(3) == 0 ? token_en_smallchars[ran.Next(token_en_smallcharlen)].ToString()[0] : token_nums[ran.Next(token_numlen)].ToString()[0];
                    }
                    sb.AppendFormat("'{0}',", new string(tokenchars));
                    break;
                case simuproptype.pwd:
                    sb.AppendFormat("'{0}',", ran.Next(100000, 1000000));
                    break;
                case simuproptype.humanheight:
                    sb.AppendFormat("{0}", ran.Next(140, 220));//cm
                    break;
                case simuproptype.humanwight:
                    sb.AppendFormat("{0}", ran.Next(30, 150));//kg
                    break;
                case simuproptype.longitude:
                    sb.AppendFormat("{0},", ran.Next(-179, 179) + ran.NextDouble());//西经为负
                    break;
                case simuproptype.latitude:
                    sb.AppendFormat("{0},", ran.Next(-89, 89) + ran.NextDouble());//南续为负
                    break;
                case simuproptype.url:
                    sb.AppendFormat("'{0}',", simures.urladdress.Rows[0][simures.urladdress.urladdress_TextColumn].ToString().Split(',')[ran.Next(simureslendic["urladdress"])]);
                    break;
                case simuproptype.guid:
                    sb.AppendFormat("{0},", Guid.NewGuid());
                    break;
                case simuproptype.phone:
                    var phone_title = simures.phonetitle.Rows[0][simures.phonetitle.phonetitle_TextColumn].ToString().Split(',')[ran.Next(simureslendic["phonetitle"])];
                    sb.AppendFormat("'{0}{1}',", phone_title, ran.Next(10000000, 100000000));
                    break;
                case simuproptype.percentage:
                    sb.AppendFormat("{0}", ran.Next(99) + ran.NextDouble());
                    break;
                case simuproptype.goods:
                    break;
                case simuproptype.bit:
                    sb.AppendFormat("{0},", ran.Next(2));
                    break;
                case simuproptype.devicename:
                    break;
                case simuproptype.devicenum:
                    break;
                case simuproptype.none:
                    sb.AppendFormat("{0},", "NULL");
                    break;
                case simuproptype.enumname:
                    sb.AppendFormat("'{0}',", simures.en_surname.Rows[0][simures.en_surname.en_surname_TextColumn].ToString().Split(',')[ran.Next(simureslendic["en_surname"])]);
                    break;
                case simuproptype.position:
                    var position_s = from item in simures.Tables.Cast<DataTable>() where item.Rows[0]["tag"].ToString() == "pos" select item;
                    var position_len = position_s.Count();
                    var position_current = position_s.ToArray()[ran.Next(position_len)];
                    var position_content = position_current.Rows[0][position_current.Columns.Count - 1].ToString().Split(',');
                    sb.AppendFormat("'{0}',", position_content[ran.Next(position_content.Length)]);
                    break;
                case simuproptype.describe:
                    var describe_content = simures.describe.Rows[0][simures.describe.describe_TextColumn].ToString().Split(';')[ran.Next(simureslendic["describe"])];
                    sb.AppendFormat("'{0}',", describe_content.Substring(0, describe_content.Length > ran2 ? ran2 : describe_content.Length));
                    break;
                case simuproptype.xml:
                    var xml_one = simures.xml.Rows[0][simures.xml.xml_TextColumn].ToString().Split(',')[ran.Next(simureslendic["xml"])];
                    if (ran2 > 0)
                        sb.AppendFormat("'{0}',", new string(File.ReadAllText(Environment.CurrentDirectory.Replace(@"\bin\Release", string.Empty) + xml_one, System.Text.Encoding.Default).Take(ran2).ToArray()));
                    else
                        sb.AppendFormat("'{0}',", File.ReadAllText(Environment.CurrentDirectory.Replace(@"\bin\Release", string.Empty) + xml_one, System.Text.Encoding.Default));
                    break;
                case simuproptype.article:
                    var article_one = simures.article.Rows[0][simures.article.article_TextColumn].ToString().Split(',')[ran.Next(simureslendic["article"])];
                    if (ran2 > 0)
                        sb.AppendFormat("'{0}',", new string(File.ReadAllText(Environment.CurrentDirectory.Replace(@"\bin\Release", string.Empty) + article_one, System.Text.Encoding.Default).Take(ran2).ToArray()));
                    else
                        sb.AppendFormat("'{0}',", File.ReadAllText(Environment.CurrentDirectory.Replace(@"\bin\Release", string.Empty) + article_one, System.Text.Encoding.Default));
                    break;
                case simuproptype.list:
                    sb.AppendFormat("'{0}',", "list_type");
                    break;
                case simuproptype.foreignkey:
                    sb.AppendFormat("{0},", ran.Next(1, fkinfo[table] + 1));
                    break;
                default:
                    break;
            }
        }
        #endregion
        //*/
        static public void GenerateSimulateXsdClass(string input, string path) {
            var pattern = @"(?<=create table\s+)(?<class>\w+_?\w+)\((?<props>(([^\(\)])|(?<open>\()|(?<-open>\)))*)(?(open)(?!))\)";
            var r = new Regex(pattern);
            var x = r.Matches(input);
            var sb = new StringBuilder();
            foreach (Match item in x) {
                var sps = "        ";
                foreach (Capture table in item.Groups["class"].Captures) {
                    sb.AppendLine(string.Format("{0}<xs:element name='{1}'>", sps, table.Value));
                    sb.AppendLine(string.Format("{0}<xs:complexType>", sps += "  "));
                    sb.AppendLine(string.Format("{0}<xs:sequence>", sps += "  "));
                }
                foreach (Capture props in item.Groups["props"].Captures) {
                    var row = Regex.Split(props.Value, @"\r\n");
                    foreach (var prop in row) {
                        var pattern2 = @"(?<!-+\w+\s*[\r\n]\s*?)(?<=[\r\n,\[]?\s*)\w+(?=\]?)\b";
                        var propName = Regex.Match(prop, pattern2).Value;
                        if (!string.IsNullOrEmpty(propName)) {
                            sb.AppendLine(string.Format("{0}<xs:element name='{1}'>", sps += "  ", propName));
                            sb.AppendLine(string.Format("{0}<xs:complexType>", sps += "  "));
                            sb.AppendLine(string.Format("{0}<xs:attribute name='simuproptype' type='simuproptype'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='range'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='minmax'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='fk_table_col'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='enum_count'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='list_type'/>", sps));
                            sb.AppendLine(string.Format("{0}</xs:complexType>", sps = sps.Remove(sps.Length - 2)));
                            sb.AppendLine(string.Format("{0}</xs:element>", sps = sps.Remove(sps.Length - 2)));
                        }
                    }
                }
                foreach (Capture table in item.Groups["class"].Captures) {
                    //sb.AppendLine(string.Format("{0}", "}"));
                    sb.AppendLine(string.Format("{0}</xs:sequence>", sps = sps.Remove(sps.Length - 2)));
                    sb.AppendLine(string.Format("{0}<xs:attribute name='rows' type='xs:int'/>", sps));
                    sb.AppendLine(string.Format("{0}<xs:attribute name='order' type='xs:int'/>", sps));
                    sb.AppendLine(string.Format("{0}<xs:attribute name='outrows' type='xs:int'/>", sps));
                    sb.AppendLine(string.Format("{0}</xs:complexType>", sps = sps.Remove(sps.Length - 2)));
                    sb.AppendLine(string.Format("{0}</xs:element>", sps = sps.Remove(sps.Length - 2)));
                }
            }
            var content = Razor.Parse(Properties.Resources.simusetxsd, new { tables = sb.ToString() });
            content = content.Replace("&lt;", "<");
            content = content.Replace("&gt;", ">");
            content = content.Replace("&#39;", "'");//转换成 单引号
            SaveTo(path, content);
        }
        static public void GenerateSimulateXsdSetting(string input, string path) {
            var pattern = @"(?<=create table\s+)(?<class>\w+_?\w+)\((?<props>(([^\(\)])|(?<open>\()|(?<-open>\)))*)(?(open)(?!))\)";
            var r = new Regex(pattern);
            var x = r.Matches(input);
            var sb = new StringBuilder();
            var sb2 = new StringBuilder();
            var order = 0;
            foreach (Match item in x) {
                var sps = "        "; var sps2 = "    ";
                foreach (Capture table in item.Groups["class"].Captures) {
                    sb.AppendLine(string.Format("{0}<xs:element name='{1}'>", sps, table.Value));
                    sb.AppendLine(string.Format("{0}<xs:complexType>", sps += "  "));
                    sb.AppendLine(string.Format("{0}<xs:sequence>", sps += "  "));
                    sb2.AppendLine(string.Format("{0}<{1} rows='0' order='{2}' outrows='0'>", sps2, table.Value, order++));
                    sps2 += "  ";
                }
                foreach (Capture props in item.Groups["props"].Captures) {
                    var row = Regex.Split(props.Value, @"\r\n");
                    foreach (var prop in row) {
                        var pattern2 = @"(?<!-+\w+\s*[\r\n]\s*?)(?<=[\r\n,\[]?\s*)\w+(?=\]?)\b";
                        var propName = Regex.Match(prop, pattern2).Value;
                        if (!string.IsNullOrEmpty(propName)) {
                            sb.AppendLine(string.Format("{0}<xs:element name='{1}'>", sps += "  ", propName));
                            sb.AppendLine(string.Format("{0}<xs:complexType>", sps += "  "));
                            sb.AppendLine(string.Format("{0}<xs:attribute name='simuproptype' type='simuproptype'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='range'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='minmax'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='fk_table_col'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='enum_count'/>", sps));
                            sb.AppendLine(string.Format("{0}<xs:attribute ref='list_type'/>", sps));
                            sb.AppendLine(string.Format("{0}</xs:complexType>", sps = sps.Remove(sps.Length - 2)));
                            sb.AppendLine(string.Format("{0}</xs:element>", sps = sps.Remove(sps.Length - 2)));
                            sb2.AppendLine(string.Format("{0}<{1} simuproptype='none'/>", sps2, propName));
                        }
                    }
                }
                foreach (Capture table in item.Groups["class"].Captures) {
                    sb.AppendLine(string.Format("{0}</xs:sequence>", sps = sps.Remove(sps.Length - 2)));
                    sb.AppendLine(string.Format("{0}<xs:attribute name='rows' type='xs:int'/>", sps));
                    sb.AppendLine(string.Format("{0}<xs:attribute name='order' type='xs:int'/>", sps));
                    sb.AppendLine(string.Format("{0}<xs:attribute name='outrows' type='xs:int'/>", sps));
                    sb.AppendLine(string.Format("{0}</xs:complexType>", sps = sps.Remove(sps.Length - 2)));
                    sb.AppendLine(string.Format("{0}</xs:element>", sps = sps.Remove(sps.Length - 2)));
                    sb2.AppendLine(string.Format("{0}</{1}>", sps2 = sps2.Remove(sps.Length - 2), table.Value));
                }
            }
            var content = Razor.Parse(Properties.Resources.simuset, new { tables = sb.ToString(), settingDefault = sb2.ToString() });
            content = content.Replace("&lt;", "<");
            content = content.Replace("&gt;", ">");
            content = content.Replace("&#39;", "'");//转换成 单引号
            SaveTo(path, content);
        }
        /// <summary>
        /// 根据输入sql脚本生成映射实体类集
        /// </summary>
        /// <param name="input"></param>
        /// <param name="isNotify"></param>
        /// <returns></returns>
        static public string GenerateEntityBase(string input, bool isNotify = false) {
            var pattern = @"(?<=create table\s+)(?<class>\w+_?\w+)\((?<props>(([^\(\)])|(?<open>\()|(?<-open>\)))*)(?(open)(?!))\)";

            var r = new Regex(pattern);
            var x = r.Matches(input);
            var sb = new StringBuilder();
            foreach (Match x2 in x) {
                foreach (Capture item in x2.Groups["class"].Captures) {
                    if (isNotify) {
                        sb.AppendLine(string.Format("public class {0} : INotifyPc {1}", item.Value, "{"));
                        sb.AppendLine("public Command Act { get; set; }");
                        sb.AppendLine("public object ActParam { get; set; }");
                        sb.AppendLine("public void OnPropertyChanged(string pn) {");
                        sb.AppendLine("if (PropertyChanged != null) {");
                        sb.AppendLine("PropertyChanged.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(pn));");
                        sb.AppendLine("}");
                        sb.AppendLine("}");
                        sb.AppendLine("public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;");

                        //sb.AppendLine("public dynamic Entity{get;set;}");
                        //sb.AppendLine("public Command MouseLeftDown { get; set; }");
                        //sb.AppendLine("public object MouseLeftDownParam { get; set; }");
                        //sb.AppendLine("public Command MouseLeftUp { get; set; }");
                        //sb.AppendLine("public object MouseLeftUpParam { get; set; }");
                        //sb.AppendLine("public Command MouseRightDown { get; set; }");
                        //sb.AppendLine("public object MouseRightDownParam { get; set; }");
                        //sb.AppendLine("public Command MouseRightUp { get; set; }");
                        //sb.AppendLine("public object MouseRightUpParam { get; set; }");
                    } else {
                        sb.AppendLine(string.Format("public class {0}{1}", item.Value, "{"));
                    }
                }
                foreach (Capture item in x2.Groups["props"].Captures) {
                    //Console.WriteLine(item.Value);
                    //var row2 = item.Value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    var row = Regex.Split(item.Value, @"\r\n");
                    foreach (var prop in row) {
                        var pattern2 = @"(?<!-+\w+\s*[\r\n]\s*?)(?<=[\r\n,\[]?\s*)\w+(?=\]?)\b";
                        var pattern3 = @"\s?\[?(int|tinyint|varchar|bit|datetime|decimal|float|image|money|ntext|nvarchar|smalldatetime|smallint|text|bigint|binary|char|nchar|numeric|real|smallmoney|sql_variant|timestamp|uniqueidentifier|varbinary|xml)\]?\s?";
                        //var pantter4 = @"\((?:\d{1,5}|max)\)?";
                        //var pantter5 = @"(?<=references\s+)\w+(?=\W)";
                        var propName = Regex.Match(prop, pattern2).Value;
                        var pt = Regex.Match(prop, pattern3);
                        var propType = string.Empty;
                        if (isNotify)
                            propType = SqlTypeName2DotNetType2(pt.Groups[0].Value);
                        else
                            propType = SqlTypeName2DotNetType(pt.Groups[0].Value);
                        if (!string.IsNullOrEmpty(propName) && !string.IsNullOrEmpty(propType)) {
                            if (propName == "Tag") {
                                sb.AppendLine(string.Format("public dynamic {0}{1}get;set;{2}", propName, "{", "}"));
                            } else {
                                sb.AppendLine(string.Format("public {0} {1}{2}get;set;{3}", propType, propName, "{", "}"));
                            }
                        }
                        //var relationship = Regex.Match(prop, pantter5).Value;
                        //if (!string.IsNullOrEmpty(relationship)) {
                        //    Console.WriteLine(relationship);
                        //}
                    }
                }
                foreach (Capture item in x2.Groups["class"].Captures) {
                    sb.AppendLine(string.Format("{0}", "}"));
                }
            }
            //Console.WriteLine(sb.ToString());
            //Clipboard.SetText(sb.ToString());
            return sb.ToString();
        }
        /// <summary>  
        /// 将SQLServer数据类型（如：varchar）转换为.Net类型（如：String）
        /// </summary>  
        /// <param name="sqlTypeString">SQLServer数据类型</param>  
        /// <returns>net type string</returns>  
        static public string SqlTypeName2DotNetType(string sqlTypeString) {
            if (string.IsNullOrEmpty(sqlTypeString)) return string.Empty;
            string[] SqlTypeNames = new string[] { "int", "varchar", "bit", "datetime", "decimal", "float", "image", "money", "ntext", "nvarchar", "smalldatetime", "smallint", "text", "bigint", "binary", "char", "nchar", "numeric", "real", "smallmoney", "sql_variant", "timestamp", "tinyint", "uniqueidentifier", "varbinary", "xml" };
            string[] DotNetTypes = new string[] { "int", "string", "bool", "DateTime", "Decimal", "Double", "Byte[]", "Single", "string", "string", "DateTime", "Int16", "string", "Int64", "Byte[]", "string", "string", "Decimal", "Single", "Single", "Object", "Byte[]", "Byte", "Guid", "Byte[]", "string" };
            var mark = sqlTypeString.ToLower().Trim();
            int i = Array.IndexOf(SqlTypeNames, mark);
            return DotNetTypes[i];
        }
        /// <summary>
        /// 将sql中的int 不映射为C#中的int 而映射为uint
        /// </summary>
        /// <param name="sqlTypeString"></param>
        /// <returns></returns>
        static public string SqlTypeName2DotNetType2(string sqlTypeString) {
            if (string.IsNullOrEmpty(sqlTypeString)) return string.Empty;
            string[] SqlTypeNames = new string[] { "int", "varchar", "bit", "datetime", "decimal", "float", "image", "money", "ntext", "nvarchar", "smalldatetime", "smallint", "text", "bigint", "binary", "char", "nchar", "numeric", "real", "smallmoney", "sql_variant", "timestamp", "tinyint", "uniqueidentifier", "varbinary", "xml" };
            string[] DotNetTypes = new string[] { "uint", "string", "bool", "DateTime", "Decimal", "Double", "Byte[]", "Single", "string", "string", "DateTime", "Int16", "string", "Int64", "Byte[]", "string", "string", "Decimal", "Single", "Single", "Object", "Byte[]", "Byte", "Guid", "Byte[]", "string" };
            var mark = sqlTypeString.ToLower().Trim();
            int i = Array.IndexOf(SqlTypeNames, mark);
            return DotNetTypes[i];
        }
        /*
         * xsd的 基础数据类型
         * time,dateTime,date,gYear,gDay,gMonth,gYearMonth,gMonthDay,anytype,anyURI,base64Binary,duration,ENTITIES,ENTITY,hexBinary,ID,IDREF,IDREFS,language,Name,NCName,NMTOKEN,NMTOKENS,normalizedString,NOTATION,QName,string,token,boolean,decimal,float,double,byte,int,integer,long,negativeInteger,nonNegativeInteger,nonPositiveInteger,positiveInteger,short,unsignedByte,unsignedInt,unsignedLong,unsignedShort
         */
        static public string SqlTypeName2XsdType(string sqltypename) {
            if (string.IsNullOrEmpty(sqltypename)) return string.Empty;
            string[] SqlTypeNames = new string[] { "int", "varchar", "bit", "datetime", "decimal", "float", "image", "money", "ntext", "nvarchar", "smalldatetime", "smallint", "text", "bigint", "binary", "char", "nchar", "numeric", "real", "smallmoney", "sql_variant", "timestamp", "tinyint", "uniqueidentifier", "varbinary", "xml" };
            string[] XsdTypes = new string[] { "int", "string", "boolean", "dateTime", "decimal", "float", "base64Binary", "float", "string", "string", "dateTime", "short", "string", "long", "hexBinary", "string", "string", "decimal", "float", "float", "anytype", "hexBinary", "byte", "token", "base64Binary", "string" };
            var mark = sqltypename.ToLower().Trim();
            int i = Array.IndexOf(SqlTypeNames, mark);
            return XsdTypes[i];
        }
        static public string GenerateEntityCtx(string input, string dbc) {
            var pattern = @"(?<=create table\s+)(?<class>\w+_?\w+)\((?<props>(([^\(\)])|(?<open>\()|(?<-open>\)))*)(?(open)(?!))\)";
            var r = new Regex(pattern);
            var x = r.Matches(input);
            var sb = new StringBuilder();
            sb.AppendLine(string.Format("public class {0}:DbContext{1}", dbc, "{"));
            foreach (Match x2 in x) {
                foreach (Capture item in x2.Groups["class"].Captures) {
                    sb.AppendLine(string.Format("public DbSet<{0}> p{1} {2}get;set;{3}", item.Value, item.Value, "{", "}"));
                }
            }
            sb.AppendLine(string.Format("public {0}(string con):base(con){1}", dbc, "{"));
            sb.AppendLine(string.Format("{0}", "}"));
            sb.AppendLine(string.Format("{0}", "}"));
            //Clipboard.SetText(sb.ToString());
            return sb.ToString();
        }
        static public void GenerateEntitysCtx(string entitypath, string ctxpath, string entitysql, string ctxsql) {
            var x = Configh.Path_Root.Split('\\').Last();
            var content1 = Razor.Parse(Properties.Resources.generalcodefile, new {
                namesp = string.Format("{0}Core", x),
                clas = entitysql,
                ns1 = "using ArithCollect;",
                ns2 = "",
            });
            SaveTo(entitypath, content1);
            var content2 = Razor.Parse(Properties.Resources.generalcodefile, new {
                namesp = string.Format("{0}Dal", x),
                clas = ctxsql,
                ns1 = "using System.Data.Entity;",
                ns2 = string.Format("using {0}Core;", x),
            });
            content2 = content2.Replace("&lt;", "<");
            content2 = content2.Replace("&gt;", ">");
            SaveTo(ctxpath, content2);
        }
        static public void GenerateVmh() {
            var x = string.Format("{0}Core", Configh.Path_Root.Split('\\').Last());
            var path = Configh.Path_Vmh;
            var content = Razor.Parse(Properties.Resources.Vmh, new { usingns1 = string.Empty, ns = x });
            SaveTo(path, content);
        }
        static public bool SaveTo(string path, string content) {
            var r = false;
            using (var sw = new StreamWriter(File.Open(path, FileMode.OpenOrCreate, FileAccess.Write))) {
                sw.BaseStream.SetLength(0);
                sw.Write(content); sw.Flush();
            }
            return r;
        }
        static public void CreateVmStyleConverter(string ns, string core, string pathvsc) {
            var content = Razor.Parse(Properties.Resources.VmStyleConverter, new { theNamespace = ns, core = core });
            SaveTo(pathvsc, content);
        }
        static public void CreateVmUiStyle(string proxyns, string entitypath, string pathvus) {
            Assembly entitydll = Assembly.LoadFile(entitypath);
            Type[] entitytps = entitydll.GetTypes();
            //业务辅助界面元素类型
            IEnumerable<Type> mvmtps = from item in entitytps where Regex.IsMatch(item.Name, @"\w+Model\b") select item;
            //主体业务类型
            IEnumerable<Type> unmvmtps = from item in entitytps where Regex.IsMatch(item.Name, @"(Role|Note|R|Res|State|Lc)_\w+") select item;

            List<EntityType> ets = new List<EntityType>();//辅助业务界面元素
            foreach (Type item in mvmtps) {
                var et = new EntityType { entityName = item.Name };
                foreach (PropertyInfo item2 in item.GetProperties()) {
                    if (item2.Name != "RelatedEntity" && item2.Name != "ActParam" && item2.Name != "Act" && item2.Name != "ID" && item2.PropertyType != item && item2.PropertyType.Name != "ICollection`1") {
                        et.props.Add(new EntityProp { propName = item2.Name });
                    }
                }
                ets.Add(et);
            }
            List<EntityType> etdts = new List<EntityType>();
            foreach (Type item in unmvmtps) {
                var et = new EntityType { entityName = item.Name };
                foreach (PropertyInfo item2 in item.GetProperties()) {
                    if (item2.Name != "ID" && item2.PropertyType != item && item2.PropertyType.Name != "ICollection`1") {
                        et.props.Add(new EntityProp { propName = item2.Name, propTypeName = item2.PropertyType.Name, propGenericType1 = item2.PropertyType.GenericTypeArguments.Count() == 0 ? string.Empty : item2.PropertyType.GenericTypeArguments[0].Name });
                    }
                }
                etdts.Add(et);
            }
            /*theNamespace:Dtst.View.Main*/
            var content = Razor.Parse(Properties.Resources.vmuistyle, new { theNamespace = proxyns, ets = ets, etdts = etdts, mvmtps = mvmtps });
            //content = content.Replace("&lt;", "<");
            //content = content.Replace("&gt;", ">");
            SaveTo(pathvus, content);
        }
        //

        static void GenerateConfig(List<Type> tps, StringBuilder sb) {
            foreach (var item in tps) {
                //lts.Add(item);//ok
                sb.AppendLine(string.Format("   public class Proxy{0}:{1}{2}", item.Name, item.Name, "{"));

                sb.AppendLine(string.Format("       static Proxy{0} _deputy;", item.Name));
                sb.AppendLine(string.Format("       public static Proxy{0} Deputy {1}", item.Name, "{"));
                sb.AppendLine(string.Format("           get {0} if (_deputy == null)_deputy = new Proxy{1}(); return _deputy; {2}", "{", item.Name, "}"));
                sb.AppendLine("     }");
                var sb4 = new List<Tuple<string, string>>();
                var methods2 = item.GetMethods();
                var methods = from met in methods2 where met.GetCustomAttribute(typeof(OperationContractAttribute)) != null select met;
                sb.AppendLine(string.Format("     {0}Client cc;", item.Name));
                sb.AppendLine(string.Format("       Proxy{0}(){1}", item.Name, "{"));//构造函数
                sb.AppendLine(string.Format("           cc=new {0}Client(/* wcf client binding name*/);", item.Name));
                foreach (var method in methods) {
                    var miname = string.Format("cc_{0}Completed", method.Name);
                    sb.AppendLine(string.Format("           cc.{0}Completed+={1};", method.Name, miname));
                    sb4.Add(Tuple.Create<string, string>(method.Name, miname));
                }
                sb.AppendLine("     }");
                foreach (var comdm in sb4) {
                    sb.AppendLine(string.Format("       void {0}(object sender, {1}CompletedEventArgs e) {2}", comdm.Item2, comdm.Item1, "{"));
                    sb.AppendLine(string.Format("         try {0}Acex.WcfRpcCallback(e.Result,\"{1}\");{2}", "{", comdm.Item1, "}"));
                    sb.AppendLine(string.Format("         catch (Exception ex) {0}Acex.WcfRpcError(ex);{1}", "{", "}"));
                    sb.AppendLine("     }");
                }
                foreach (var method in methods) {
                    var mps = method.GetParameters();
                    var mpslen = mps.Length;
                    var sb2 = new StringBuilder();
                    var sb3 = new StringBuilder();
                    foreach (var pi in mps) {
                        sb2.Append(string.Format("{0} {1},", pi.ParameterType, pi.Name));
                        sb3.Append(string.Format("{0},", pi.Name));
                    }
                    if (sb2.Length > 0)
                        sb2.Remove(sb2.Length - 1, 1);
                    var sb2v = sb2.ToString();
                    if (sb3.Length > 0)
                        sb3.Remove(sb3.Length - 1, 1);
                    var sb3v = sb3.ToString();
                    if (method.ReturnType == typeof(void)) {
                        sb.AppendLine(string.Format("       public void {0}({1}){2}", method.Name, sb2v, "{"));
                        sb.AppendLine(string.Format("           cc.{0}Async({1});", method.Name, sb3v));
                        sb.AppendLine("}");
                    } else {
                        sb.AppendLine(string.Format("       public {0} {1}({2}){3}", method.ReturnType.Name, method.Name, sb2v, "{"));
                        sb.AppendLine(string.Format("           cc.{0}Async({1});", method.Name, sb3v));
                        sb.AppendLine(string.Format("         return default({0});", method.ReturnType.Name));
                        sb.AppendLine("     }");
                    }
                }
                sb.AppendLine(" }");
            }
        }
        static void GenerateConfigD(List<Type> tps, StringBuilder sb) {
            foreach (var item in tps) {
                //lts.Add(item);//ok
                sb.AppendLine(string.Format("   public class Proxy{0}:{1}{2}", item.Name, item.Name, "{"));
                /*
                 * static ProxyService1 cc;
                    public static ProxyService1 Deputy {
                        get { if (cc == null)cc = new ProxyService1(); return cc; }
                    }
                 */
                sb.AppendLine(string.Format("       static Proxy{0} _deputy;", item.Name));
                sb.AppendLine(string.Format("       public static Proxy{0} Deputy {1}", item.Name, "{"));
                sb.AppendLine(string.Format("           get {0} if (_deputy == null)_deputy = new Proxy{1}(); return _deputy; {2}", "{", item.Name, "}"));
                sb.AppendLine("     }");
                var sb4 = new List<Tuple<string, string>>();
                var methods2 = item.GetMethods();
                var methods = from met in methods2 where met.GetCustomAttribute(typeof(OperationContractAttribute)) != null select met;
                sb.AppendLine("     dynamic cc;");
                sb.AppendLine(string.Format("       public Proxy{0}(){1}", item.Name, "{"));//构造函数
                sb.AppendLine(string.Format("           //cc=new {0}Client(/* wcf client binding name*/);", item.Name));
                foreach (var method in methods) {
                    var miname = string.Format("cc_{0}Completed", method.Name);
                    sb.AppendLine(string.Format("           //cc.{0}Completed+={1};", method.Name, miname));
                    sb4.Add(Tuple.Create<string, string>(method.Name, miname));
                }
                sb.AppendLine("     }");
                foreach (var comdm in sb4) {
                    /*
                        try {Acex.WcfRpcCallback(e.Result, "Welcome");}
                     * catch (Exception ex) {Acex.WcfRpcError(ex);}
                    */
                    sb.AppendLine(string.Format("       void {0}(object sender, {1} e) {2}", comdm.Item2, "dynamic", "{"));
                    sb.AppendLine(string.Format("         try {0}Acex.WcfRpcCallback(e.Result,\"{1}\");{2}", "{", comdm.Item1, "}"));
                    sb.AppendLine(string.Format("         catch (Exception ex) {0}Acex.WcfRpcError(ex);{1}", "{", "}"));
                    sb.AppendLine("     }");
                }
                foreach (var method in methods) {
                    var mps = method.GetParameters();
                    var mpslen = mps.Length;
                    var sb2 = new StringBuilder();
                    var sb3 = new StringBuilder();
                    foreach (var pi in mps) {
                        sb2.Append(string.Format("{0} {1},", pi.ParameterType, pi.Name));
                        sb3.Append(string.Format("{0},", pi.Name));
                    }
                    if (sb2.Length > 0)
                        sb2.Remove(sb2.Length - 1, 1);
                    var sb2v = sb2.ToString();
                    if (sb3.Length > 0)
                        sb3.Remove(sb3.Length - 1, 1);
                    var sb3v = sb3.ToString();
                    if (method.ReturnType == typeof(void)) {
                        sb.AppendLine(string.Format("       public void {0}({1}){2}", method.Name, sb2v, "{"));
                        sb.AppendLine(string.Format("           cc.{0}Async({1});", method.Name, sb3v));
                        sb.AppendLine("}");
                    } else {
                        sb.AppendLine(string.Format("       public {0} {1}({2}){3}", method.ReturnType.Name, method.Name, sb2v, "{"));
                        sb.AppendLine(string.Format("           cc.{0}Async({1});", method.Name, sb3v));
                        sb.AppendLine(string.Format("         return default({0});", method.ReturnType.Name));
                        sb.AppendLine("     }");
                    }
                }
                sb.AppendLine(" }");
            }
        }

        internal static void GenerateConfigSelector(string entitypath, string np, string core, string pathconfig, bool isd = true) {
            var asm = Assembly.LoadFile(entitypath);
            var tps = asm.GetTypes();
            var targetTypes = new List<Type>();
            foreach (var item in tps) {
                if (item.GetCustomAttribute(typeof(System.ServiceModel.ServiceContractAttribute)) != null) {
                    targetTypes.Add(item);
                }
            }

            var sb = new StringBuilder();
            sb.AppendLine("using System;");
            sb.AppendLine("using System.Collections;");
            sb.AppendLine("using System.Collections.Generic;");
            sb.AppendLine("using System.ServiceModel;");
            sb.AppendLine("using ArithCollect;");
            sb.AppendLine(string.Format("using {0};", core));
            sb.AppendLine();
            sb.AppendLine(string.Format("namespace {0}{1}", np, "{"));
            if (isd)
                GenerateConfigD(targetTypes, sb);
            else
                GenerateConfig(targetTypes, sb);
            sb.AppendLine("}");
            SaveTo(pathconfig, sb.ToString());
        }

        internal static void GenerateUiContainer(string path, string ns) {
            var content = Razor.Parse(Properties.Resources.UiContainer, new { ns = ns });
            SaveTo(path, content);
        }
    }
    //
    public static class CodeTimer {
        public static void Initialize() {
            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
            Thread.CurrentThread.Priority = ThreadPriority.Highest;
            Time("", 1, () => { });
        }
        public static void Time(string name, int iteration, Action action) {
            if (String.IsNullOrEmpty(name)) return;
            // 1.
            ConsoleColor currentForeColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine(name);
            // 2.
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            int[] gcCounts = new int[GC.MaxGeneration + 1];
            for (int i = 0; i <= GC.MaxGeneration; i++) {
                gcCounts[i] = GC.CollectionCount(i);
            }
            // 3.
            Stopwatch watch = new Stopwatch();
            watch.Start();
            ulong cycleCount = GetCycleCount();
            for (int i = 0; i < iteration; i++)
                action();
            ulong cpuCycles = GetCycleCount() - cycleCount;
            watch.Stop();
            // 4.
            Console.ForegroundColor = currentForeColor;
            Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
            Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0"));
            // 5.
            for (int i = 0; i <= GC.MaxGeneration; i++) {
                int count = GC.CollectionCount(i) - gcCounts[i];
                Console.WriteLine("\tGen " + i + ": \t\t" + count);
            }
            Console.WriteLine();
        }
        private static ulong GetCycleCount() {
            ulong cycleCount = 0;
            QueryThreadCycleTime(GetCurrentThread(), ref cycleCount);
            return cycleCount;
        }
        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulong cycleTime);
        [DllImport("kernel32.dll")]
        static extern IntPtr GetCurrentThread();
    }
}
